#!/bin/bash

# Git Pull Script - Automatically handles merge conflicts by backing up local files
# Usage: ./gitpull.sh

set -e  # Exit on any error

# Make git operations non-interactive
export GIT_TERMINAL_PROMPT=0
export GIT_ASKPASS=true
export GIT_PAGER=cat  # Disable pager to prevent interactive prompts

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

echo -e "${BLUE}=== Git Pull Script ===${NC}"

# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
    echo -e "${RED}Error: Not in a git repository${NC}"
    exit 1
fi

# Get the current branch
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [[ -z "$CURRENT_BRANCH" ]]; then
    echo -e "${RED}Error: Could not determine current branch${NC}"
    exit 1
fi
echo -e "${BLUE}Current branch: ${YELLOW}$CURRENT_BRANCH${NC}"

# Auto-detect remote name (same logic as gitpush.sh)
echo -e "${BLUE}Detecting git remote...${NC}"
REMOTES=$(git remote)

if [[ -z "$REMOTES" ]]; then
    echo -e "${RED}Error: No git remotes found${NC}"
    exit 1
fi

# First, try to use the upstream remote configured for the current branch
REMOTE_NAME=""
UPSTREAM_REMOTE=""

# Get the upstream remote if configured
UPSTREAM_REF=$(git symbolic-ref -q HEAD 2>/dev/null || echo "")
if [[ -n "$UPSTREAM_REF" ]]; then
    UPSTREAM_BRANCH=$(git for-each-ref --format='%(upstream:short)' "$UPSTREAM_REF" 2>/dev/null || echo "")
    if [[ -n "$UPSTREAM_BRANCH" ]]; then
        UPSTREAM_REMOTE=$(echo "$UPSTREAM_BRANCH" | cut -d'/' -f1)
        echo -e "${BLUE}Found upstream remote: ${YELLOW}$UPSTREAM_REMOTE${NC} (tracking $UPSTREAM_BRANCH)"
    fi
fi

# Use upstream remote if it exists and is valid
if [[ -n "$UPSTREAM_REMOTE" ]] && echo "$REMOTES" | grep -q "^$UPSTREAM_REMOTE$"; then
    REMOTE_NAME="$UPSTREAM_REMOTE"
    echo -e "${BLUE}Using upstream remote: ${YELLOW}$REMOTE_NAME${NC}"
else
    # Fallback to preference order: 'origin', then 'local', then first one
    if echo "$REMOTES" | grep -q "^origin$"; then
        REMOTE_NAME="origin"
        echo -e "${BLUE}Using fallback remote: ${YELLOW}$REMOTE_NAME${NC}"
    elif echo "$REMOTES" | grep -q "^local$"; then
        REMOTE_NAME="local"
        echo -e "${BLUE}Using fallback remote: ${YELLOW}$REMOTE_NAME${NC}"
    else
        REMOTE_NAME=$(echo "$REMOTES" | head -n1)
        echo -e "${BLUE}Using fallback remote: ${YELLOW}$REMOTE_NAME${NC}"
    fi
fi

# Show remote URL
REMOTE_URL=$(git config --get remote."$REMOTE_NAME".url)
echo -e "${BLUE}Remote URL: ${YELLOW}$REMOTE_URL${NC}"

# Function to backup conflicted files
backup_files() {
    local timestamp=$(date '+%Y%m%d_%H%M%S')
    local backup_dir="backup_${timestamp}"
    
    echo -e "${YELLOW}Creating backup directory: $backup_dir${NC}"
    mkdir -p "$backup_dir"
    
    local files_backed_up=false
    
    # Backup modified/conflicted tracked files
    local modified_files
    if git status --porcelain | grep -E '^(M|UU|AA|DD)' > /dev/null; then
        modified_files=$(git status --porcelain | grep -E '^(M|UU|AA|DD)' | awk '{print $2}')
        
        echo -e "${BLUE}Backing up modified/conflicted tracked files:${NC}"
        while IFS= read -r file; do
            if [[ -f "$file" ]]; then
                echo "  - $file -> $backup_dir/$file"
                # Create directory structure in backup
                mkdir -p "$backup_dir/$(dirname "$file")"
                cp "$file" "$backup_dir/$file"
                files_backed_up=true
            fi
        done <<< "$modified_files"
    fi
    
    # Backup untracked files (excluding those in .gitignore)
    local untracked_files
    untracked_files=$(git ls-files --others --exclude-standard)
    if [[ -n "$untracked_files" ]]; then
        echo -e "${BLUE}Backing up untracked files:${NC}"
        while IFS= read -r file; do
            if [[ -f "$file" ]]; then
                echo "  - $file -> $backup_dir/$file"
                # Create directory structure in backup
                mkdir -p "$backup_dir/$(dirname "$file")"
                cp "$file" "$backup_dir/$file"
                files_backed_up=true
            fi
        done <<< "$untracked_files"
    fi
    
    if [[ "$files_backed_up" == "true" ]]; then
        echo -e "${GREEN}✓ Files backed up to $backup_dir${NC}"
        return 0
    else
        echo -e "${YELLOW}No files to backup${NC}"
        rmdir "$backup_dir" 2>/dev/null || true
        return 1
    fi
}

# Fetch latest changes first
echo -e "${BLUE}Fetching latest changes from $REMOTE_NAME...${NC}"
git fetch "$REMOTE_NAME"

# Check for both unstaged changes and untracked files
HAS_UNSTAGED_CHANGES=false
HAS_UNTRACKED_FILES=false
HAS_LOCAL_CHANGES=false

# Check for unstaged changes in tracked files
if ! git diff-index --quiet HEAD --; then
    HAS_UNSTAGED_CHANGES=true
    HAS_LOCAL_CHANGES=true
fi

# Check for untracked files (excluding those in .gitignore)
if [[ -n $(git ls-files --others --exclude-standard) ]]; then
    HAS_UNTRACKED_FILES=true
    HAS_LOCAL_CHANGES=true
fi

if [[ "$HAS_LOCAL_CHANGES" == "true" ]]; then
    if [[ "$HAS_UNSTAGED_CHANGES" == "true" ]]; then
        echo -e "${YELLOW}Found unstaged changes in tracked files${NC}"
    fi
    if [[ "$HAS_UNTRACKED_FILES" == "true" ]]; then
        echo -e "${YELLOW}Found untracked files${NC}"
    fi
    git --no-pager status --porcelain
fi

# Check if we're behind the remote
BEHIND_COUNT=$(git rev-list --count HEAD.."$REMOTE_NAME/$CURRENT_BRANCH" 2>/dev/null || echo "0")
if [[ "$BEHIND_COUNT" -eq 0 ]]; then
    echo -e "${GREEN}Already up to date${NC}"
    exit 0
fi

echo -e "${BLUE}Behind remote by $BEHIND_COUNT commits${NC}"

# Attempt to pull
echo -e "${BLUE}Attempting to pull from $REMOTE_NAME/$CURRENT_BRANCH...${NC}"

# Disable exit on error temporarily for the pull attempt
set +e
git pull "$REMOTE_NAME" "$CURRENT_BRANCH" 2>&1 | tee /tmp/git_pull_output.log
PULL_EXIT_CODE=$?
set -e

# Check if pull was successful
if [[ $PULL_EXIT_CODE -eq 0 ]]; then
    echo -e "${GREEN}✓ Successfully pulled from $REMOTE_NAME/$CURRENT_BRANCH${NC}"
else
    echo -e "${YELLOW}Pull failed, likely due to conflicts${NC}"
    
    # Check if it's a merge conflict
    if git status --porcelain | grep -E '^(UU|AA|DD)' > /dev/null || grep -i "conflict" /tmp/git_pull_output.log > /dev/null; then
        echo -e "${YELLOW}Merge conflicts detected. Backing up local files and discarding local changes...${NC}"
        
        # Backup files if there were local changes
        if [[ "$HAS_LOCAL_CHANGES" == "true" ]]; then
            backup_files
        fi
        
        # Abort any ongoing merge
        git merge --abort 2>/dev/null || true
        
        # Reset to clean state
        echo -e "${BLUE}Resetting to clean state...${NC}"
        git reset --hard HEAD
        git clean -fd
        
        # Try pull again
        echo -e "${BLUE}Attempting pull again after reset...${NC}"
        git pull "$REMOTE_NAME" "$CURRENT_BRANCH"
        echo -e "${GREEN}✓ Successfully pulled after resolving conflicts${NC}"
        
    elif grep -i "uncommitted changes" /tmp/git_pull_output.log > /dev/null; then
        echo -e "${YELLOW}Pull failed due to uncommitted changes. Backing up and discarding local changes...${NC}"
        
        # Backup local changes
        backup_files
        
        # Discard local changes
        echo -e "${BLUE}Discarding local changes...${NC}"
        git reset --hard HEAD
        git clean -fd
        
        # Try pull again
        echo -e "${BLUE}Attempting pull again after discarding changes...${NC}"
        git pull "$REMOTE_NAME" "$CURRENT_BRANCH"
        echo -e "${GREEN}✓ Successfully pulled after discarding local changes${NC}"
        
    else
        echo -e "${RED}Pull failed for unknown reason. Check the output above.${NC}"
        exit 1
    fi
fi

# Clean up temporary file
rm -f /tmp/git_pull_output.log

echo -e "${GREEN}=== Git pull completed ===${NC}" 